"""
Oracle timezone标准
"""
from typing import Dict, List, Tuple, Optional
import zoneinfo
from datetime import datetime, timedelta
from collections import namedtuple

from django.utils.translation import gettext_lazy as _


def format_offset(off: timedelta, sep=':'):
    s = ''
    if off is not None:
        if off.days < 0:
            sign = "-"
            off = -off
        else:
            sign = "+"
        hh, mm = divmod(off, timedelta(hours=1))
        mm, ss = divmod(mm, timedelta(minutes=1))
        s += "%s%02d%s%02d" % (sign, hh, sep, mm)
        if ss or ss.microseconds:
            s += "%s%02d" % (sep, ss.seconds)

            if ss.microseconds:
                s += '.%06d' % ss.microseconds
    return s


_TimeZoneItem = namedtuple('TimeZoneItem', ['name', 'display', 'description'])
class TimeZoneItem(_TimeZoneItem):
    def display_detail(self) -> str:
        tz = zoneinfo.ZoneInfo(self.name)
        offset = datetime.now(tz=tz).utcoffset()
        return f'(UTC{format_offset(off=offset)}) {self.description} ({self.display})'


class OracleTimezone:

    TIMEZONES = {
        # Niue Time, (GMT-11:00, -660)
        'Pacific/Niue': TimeZoneItem(name='Pacific/Niue', display=_('太平洋/纽埃'), description=_('纽埃时间')),
        # Samoa Standard Time,(GMT-11:00, -660)
        'Pacific/Pago_Pago': TimeZoneItem(name='Pacific/Pago_Pago', display=_('太平洋/帕果'), description=_('萨摩亚标准时间')),

        # Hawaii Standard Time,(GMT-10:00, -600)HST
        # 'HST': TimeZoneItem(name='Pacific/Honolulu', display=_('太平洋/檀香山'), description=_('夏威夷标准时间')),
        # Hawaii Standard Time,(GMT-10:00, -600)Pacific/Honolulu
        'Pacific/Honolulu': TimeZoneItem(name='Pacific/Honolulu', display=_('太平洋/檀香山'), description=_('夏威夷标准时间')),
        # 'Cook Islands Time', (GMT-10:00, -600)Pacific/Rarotonga
        'Pacific/Rarotonga': TimeZoneItem(name='Pacific/Rarotonga', display=_('太平洋/拉罗汤加'), description=_('库克群岛时间')),
        # Tahiti Time; (GMT-10:00, -600)Pacific/Tahiti
        'Pacific/Tahiti': TimeZoneItem(name='Pacific/Tahiti', display=_('太平洋/塔希提岛'), description=_('大溪地时间')),

        # Marquesas Time; (GMT-09:30, -570)Pacific/Marquesas
        'Pacific/Marquesas': TimeZoneItem(name='Pacific/Marquesas', display=_('太平洋/马克萨斯'), description=_('马克萨斯时间')),

        # Hawaii-Aleutian Standard Time,(GMT-09:00, -540)America/Adak
        'America/Adak': TimeZoneItem(name='America/Adak', display=_('美洲/埃达克'), description=_('夏威夷-阿留申标准时间')),

        # Gambier Time; (GMT-09:00, -540)Pacific/Gambier
        'Pacific/Gambier': TimeZoneItem(name='Pacific/Gambier', display=_('太平洋/甘比尔'), description=_('甘比尔时间')),

        # Alaska Standard Time; (GMT-08:00, -480)America/Anchorage
        # 'AST': TimeZoneItem(name='America/Anchorage', display=_('美国/安克雷奇'), description=_('阿拉斯加标准时间')),
        # Alaska Standard Time; (GMT-08:00, -480)America/Anchorage
        'America/Anchorage': TimeZoneItem(name='America/Anchorage', display=_('美国/安克雷奇'), description=_('阿拉斯加时间')),

        # Pitcairn Standard Time; (GMT-08:00, -480)Pacific/Pitcairn
        'Pacific/Pitcairn': TimeZoneItem(name='Pacific/Pitcairn', display=_('太平洋/皮特凯恩'), description=_('皮特凯恩标准时间')),

        # Pacific Standard Time; (GMT-07:00, -420)
        'America/Los_Angeles': TimeZoneItem(name='America/Los_Angeles', display=_('美国/洛杉矶'), description=_('太平洋标准时间')),
        'America/Tijuana': TimeZoneItem(name='America/Tijuana', display=_('美洲/蒂华纳'), description=_('太平洋标准时间')),
        'America/Vancouver': TimeZoneItem(name='America/Vancouver', display=_('美洲/温哥华'), description=_('太平洋标准时间')),
        # 'PST': TimeZoneItem(name='America/Los_Angeles', display=_('美国/洛杉矶'), description=_('太平洋标准时间')),

        # Mountain Standard Time; (GMT-07:00, -420)America/Dawson_Creek
        'America/Dawson_Creek': TimeZoneItem(name='America/Dawson_Creek', display=_('北美洲/道森克里克'), description=_('北美山区标准时间')),
        # Mountain Standard Time; (GMT-07:00, -420)America/Mazatlan
        'America/Mazatlan': TimeZoneItem(name='America/Mazatlan', display=_('美洲/马萨特兰'), description=_('北美山区标准时间')),
        # Mountain Standard Time; (GMT-07:00, -420)America/Phoenix
        'America/Phoenix': TimeZoneItem(name='America/Phoenix', display=_('美洲/凤凰城'), description=_('北美山区标准时间')),
        # Mountain Standard Time;(GMT-07:00, -420)MST
        # 'MST': TimeZoneItem(name='America/Phoenix', display=_('美洲/凤凰城'), description=_('北美山区标准时间')),
        # Mountain Standard Time
        # 'PNT': TimeZoneItem(name='', display=_(''), description=_('')),

        # Mountain Standard Time; (GMT-06:00, -360)America/Denver
        'America/Denver': TimeZoneItem(name='America/Denver', display=_('美国/丹佛'), description=_('北美山区时间')),
        # Mountain Standard Time; (GMT-06:00, -360)America/Edmonton
        'America/Edmonton': TimeZoneItem(name='America/Edmonton', display=_('美洲/埃德蒙顿'), description=_('北美山区时间')),

        # Central Standard Time;(GMT-06:00, -360)America/Belize
        'America/Belize': TimeZoneItem(name='America/Belize', display=_('美洲/伯利兹'), description=_('北美中部标准时间')),
        # Central Standard Time;(GMT-06:00, -360)America/Chicago
        'America/Chicago': TimeZoneItem(name='America/Chicago', display=_('美国/芝加哥'), description=_('北美中部标准时间')),
        # Central Standard Time;(GMT-06:00, -360)America/Costa_Rica
        'America/Costa_Rica': TimeZoneItem(name='America/Costa_Rica', display=_('美洲/哥斯达黎加'), description=_('北美中部标准时间')),
        # Central Standard Time;(GMT-06:00, -360)America/El_Salvador
        'America/El_Salvador': TimeZoneItem(name='America/El_Salvador', display=_('美洲/萨尔瓦多'), description=_('北美中部标准时间')),
        # Central Standard Time;(GMT-06:00, -360)America/Guatemala
        'America/Guatemala': TimeZoneItem(name='America/Guatemala', display=_('美洲/危地马拉'), description=_('北美中部标准时间')),
        # Central Standard Time;(GMT-06:00, -360)America/Managua
        'America/Managua': TimeZoneItem(name='America/Managua', display=_('美洲/马那瓜'), description=_('北美中部标准时间')),
        # Central Standard Time;(GMT-06:00, -360)America/Mexico_City
        'America/Mexico_City': TimeZoneItem(name='America/Mexico_City', display=_('美洲/墨西哥城'), description=_('北美中部标准时间')),
        # Central Standard Time;(GMT-06:00, -360)America/Regina
        'America/Regina': TimeZoneItem(name='America/Regina', display=_('美洲/里贾纳'), description=_('北美中部标准时间')),
        # Central Standard Time;(GMT-06:00, -360)America/Tegucigalpa
        'America/Tegucigalpa': TimeZoneItem(name='America/Tegucigalpa', display=_('美洲/特古西加尔巴'), description=_('北美中部标准时间')),
        # Central Standard Time；GMT-06:00, -360
        # 'CST': TimeZoneItem(name='America/Chicago', display=_('美国/芝加哥'), description=_('北美中部标准时间')),

        # Easter Islands Time;(GMT-06:00, -360)Pacific/Easter
        'Pacific/Easter': TimeZoneItem(name='Pacific/Easter', display=_('太平洋/复活节岛'), description=_('复活节岛时间')),
        # Galapagos Time;(GMT-06:00, -360)Pacific/Galapagos
        'Pacific/Galapagos': TimeZoneItem(name='Pacific/Galapagos', display=_('太平洋/加拉帕戈斯群岛'), description=_('加拉帕戈斯时间')),
        # Central Standard Time;(GMT-05:00, -300)America/Winnipeg
        'America/Winnipeg': TimeZoneItem(name='America/Winnipeg', display=_('北美/温尼伯'), description=_('北美中部时间')),
        # Colombia Time;(GMT-05:00, -300)America/Bogota
        'America/Bogota': TimeZoneItem(name='America/Bogota', display=_('美洲/波哥大'), description=_('哥伦比亚时间')),
        # Ecuador Time;(GMT-05:00, -300)America/Guayaquil
        'America/Guayaquil': TimeZoneItem(name='America/Guayaquil', display=_('美洲/瓜亚基尔'), description=_('厄瓜多尔时间')),
        # Eastern Standard Time;(GMT-05:00, -300)America/Cayman
        'America/Cayman': TimeZoneItem(name='America/Cayman', display=_('美洲/开曼群岛'), description=_('北美东部标准时间')),
        # Eastern Standard Time;(GMT-05:00, -300)America/Jamaica
        'America/Jamaica': TimeZoneItem(name='America/Jamaica', display=_('美洲/牙买加'), description=_('北美东部时间')),
        # Eastern Standard Time;(GMT-05:00, -300)America/Panama
        'America/Panama': TimeZoneItem(name='America/Panama', display=_('美洲/巴拿马'), description=_('北美东部时间')),
        # Peru Time；(GMT-05:00, -300)America/Lima
        'America/Lima': TimeZoneItem(name='America/Lima', display=_('美洲/利马'), description=_('北美东部标准时间')),
        # Acre Time；(GMT-05:00, -300)America/Porto_Acre; 已弃用
        # 'America/Porto_Acre': TimeZoneItem(name='America/Porto_Acre', display=_('巴西/波特罗阿克里'), description=_('阿克里时间')),
        # Acre Time；(GMT-05:00, -300)America/Rio_Branco
        'America/Rio_Branco': TimeZoneItem(name='America/Rio_Branco', display=_('巴西/里奥布朗库'), description=_('阿克里时间')),
        # Eastern Standard Time; GMT-05:00
        # 'EST': TimeZoneItem(name='EST', display=_('EST'), description=_('北美东部标准时间')),
        # 'IET': 'Eastern Standard Time',

        # Eastern Standard Time;(GMT-04:00, -240)America/Grand_Turk
        'America/Grand_Turk': TimeZoneItem(name='America/Grand_Turk', display=_('美洲/大特克'), description=_('北美东部时间')),
        # Central Standard Time; (GMT-04:00, -240)America/Havana
        'America/Havana': TimeZoneItem(name='America/Havana', display=_('美洲/哈瓦那'), description=_('古巴时间')),
        # Eastern Standard Time;(GMT-04:00, -240)America/Indianapolis
        'America/Indianapolis': TimeZoneItem(name='America/Indianapolis', display=_('美国/印第安纳波利斯'), description=_('北美东部时间')),
        # # Eastern Standard Time;(GMT-04:00, -240)America/Montreal
        'America/Montreal': TimeZoneItem(name='America/Montreal', display=_('美洲/蒙特利尔'), description=_('北美东部时间')),
        # Eastern Standard Time;(GMT-04:00, -240)America/Nassau
        'America/Nassau': TimeZoneItem(name='America/Nassau', display=_('美洲/拿骚'), description=_('北美东部时间')),
        # Eastern Standard Time;(GMT-04:00, -240)America/New_York
        'America/New_York': TimeZoneItem(name='America/New_York', display=_('美国/纽约'), description=_('北美东部时间')),
        # Eastern Standard Time;(GMT-04:00, -240)America/Port-au-Prince
        'America/Port-au-Prince': TimeZoneItem(name='America/Port-au-Prince', display=_('美洲/太子港'), description=_('北美东部时间')),

        # Atlantic Standard Time;(GMT-04:00, -240)America/Anguilla
        'America/Anguilla': TimeZoneItem(name='America/Anguilla', display=_('美洲/安圭拉'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Antigua
        'America/Antigua': TimeZoneItem(name='America/Antigua', display=_('美洲/安提瓜'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Aruba
        'America/Aruba': TimeZoneItem(name='America/Aruba', display=_('美洲/阿鲁巴'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Barbados
        'America/Barbados': TimeZoneItem(name='America/Barbados', display=_('美洲/巴巴多斯'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Curacao
        'America/Curacao': TimeZoneItem(name='America/Curacao', display=_('美洲/库拉索'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Dominica
        'America/Dominica': TimeZoneItem(name='America/Dominica', display=_('美洲/多米尼加'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Grenada
        'America/Grenada': TimeZoneItem(name='America/Grenada', display=_('美洲/格林纳达'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Guadeloupe
        'America/Guadeloupe': TimeZoneItem(name='America/Guadeloupe', display=_('美洲/瓜德罗普岛'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Martinique
        'America/Martinique': TimeZoneItem(name='America/Martinique', display=_('美洲/马提尼克岛'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Montserrat
        'America/Montserrat': TimeZoneItem(name='America/Montserrat', display=_('美洲/蒙特塞拉特'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Port_of_Spain
        'America/Port_of_Spain': TimeZoneItem(name='America/Port_of_Spain', display=_('美洲/西班牙港'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Puerto_Rico
        'America/Puerto_Rico': TimeZoneItem(name='America/Puerto_Rico', display=_('美洲/波多黎各'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Santo_Domingo
        'America/Santo_Domingo': TimeZoneItem(name='America/Santo_Domingo', display=_('美洲/圣多明各'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/St_Kitts
        'America/St_Kitts': TimeZoneItem(name='America/St_Kitts', display=_('美洲/圣基茨'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/St_Lucia
        'America/St_Lucia': TimeZoneItem(name='America/St_Lucia', display=_('美洲/圣卢西亚'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/St_Thomas
        'America/St_Thomas': TimeZoneItem(name='America/St_Thomas', display=_('美洲/圣托马斯'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/St_Vincent
        'America/St_Vincent': TimeZoneItem(name='America/St_Vincent', display=_('美洲/圣文森特'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-04:00, -240)America/Tortola
        'America/Tortola': TimeZoneItem(name='America/Tortola', display=_('美洲/托尔托拉岛'), description=_('大西洋标准时间')),

        # Paraguay Time;(GMT-04:00, -240)America/Asuncion
        'America/Asuncion': TimeZoneItem(name='America/Asuncion', display=_('美洲/亚松森'), description=_('巴拉圭时间')),
        # Venezuela Time;(GMT-04:00, -240)America/Caracas
        'America/Caracas': TimeZoneItem(name='America/Caracas', display=_('美洲/加拉加斯'), description=_('委内瑞拉时间')),
        # Amazon Standard Time;(GMT-04:00, -240)America/Cuiaba
        'America/Cuiaba': TimeZoneItem(name='America/Cuiaba', display=_('美洲/库亚巴'), description=_('亚马逊标准时间')),
        # Guyana Time;(GMT-04:00, -240)America/Guyana
        'America/Guyana': TimeZoneItem(name='America/Guyana', display=_('美洲/圭亚那'), description=_('圭亚那时间')),
        # Bolivia Time;(GMT-04:00, -240)America/La_Paz
        'America/La_Paz': TimeZoneItem(name='America/La_Paz', display=_('美洲/拉巴斯'), description=_('玻利维亚时间')),
        # Amazon Standard Time;(GMT-04:00, -240)America/Manaus
        'America/Manaus': TimeZoneItem(name='America/Manaus', display=_('美洲/马瑙斯'), description=_('亚马逊标准时间')),
        # Chile Time;(GMT-04:00, -240)America/Santiago
        'America/Santiago': TimeZoneItem(name='America/Santiago', display=_('美洲/圣地亚哥'), description=_('智利时间')),

        # Atlantic Standard Time;(GMT-03:00, -180)America/Halifax
        'America/Halifax': TimeZoneItem(name='America/Halifax', display=_('美国/哈利法克斯'), description=_('大西洋标准时间')),
        # Atlantic Standard Time;(GMT-03:00, -180)America/Thule
        'America/Thule': TimeZoneItem(name='America/Thule', display=_('美洲/图勒'), description=_('大西洋时间')),
        # Atlantic Standard Time;(GMT-03:00, -180)Atlantic/Bermuda
        'Atlantic/Bermuda': TimeZoneItem(name='Atlantic/Bermuda', display=_('大西洋/百慕大'), description=_('大西洋时间')),
        # 'PRT': 'Atlantic Standard Time',

        # Chile Time;(GMT-03:00, -180)Antarctica/Palmer
        'Antarctica/Palmer': TimeZoneItem(name='Antarctica/Palmer', display=_('南极洲/帕尔默'), description=_('智利时间')),
        # Falkland Is. Time;(GMT-03:00, -180)Atlantic/Stanley
        'Atlantic/Stanley': TimeZoneItem(name='Atlantic/Stanley', display=_('大西洋/斯坦利'), description=_('福克兰群岛时间')),

        # 'AGT': 'Argentine Time',
        # Argentine Time;(GMT-03:00, -180)America/Buenos_Aires
        'America/Buenos_Aires': TimeZoneItem(name='America/Buenos_Aires', display=_('美洲/布宜诺斯艾利斯'), description=_('阿根廷时间')),

        # French Guiana Time;(GMT-03:00, -180)America/Cayenne
        'America/Cayenne': TimeZoneItem(name='America/Cayenne', display=_('美洲/卡宴'), description=_('法属圭亚那时间')),
        # Brazil Time;(GMT-03:00, -180)America/Fortaleza
        'America/Fortaleza': TimeZoneItem(name='America/Fortaleza', display=_('美洲/福塔雷萨'), description=_('巴西时间')),
        # Brazil Time;(GMT-03:00, -180)America/Sao_Paulo
        'America/Sao_Paulo': TimeZoneItem(name='America/Sao_Paulo', display=_('美洲/圣保罗'), description=_('巴西时间')),
        # 'BET': 'Brazil Time',

        # Uruguay Time;(GMT-03:00, -180)America/Montevideo
        'America/Montevideo': TimeZoneItem(name='America/Montevideo', display=_('美洲/蒙得维的亚'), description=_('乌拉圭时间')),
        # Suriname Time;(GMT-03:00, -180)America/Paramaribo
        'America/Paramaribo': TimeZoneItem(name='America/Paramaribo', display=_('美洲/帕拉马里博'), description=_('苏里南时间')),

        # Newfoundland Standard Time;(GMT-02:30, -150)America/St_Johns
        'America/St_Johns': TimeZoneItem(name='America/St_Johns', display=_('美洲/圣约翰'), description=_('纽芬兰标准时间')),
        # 'CNT': 'Newfoundland Standard Time',

        # Pierre & Miquelon Standard Time;(GMT-02:00, -120)America/Miquelon
        'America/Miquelon': TimeZoneItem(name='America/Miquelon', display=_('美洲/密克隆'), description=_('皮埃尔和密克隆标准时间')),
        # Fernando de Noronha Time;(GMT-02:00, -120)America/Noronha
        'America/Noronha': TimeZoneItem(name='America/Noronha', display=_('美洲/诺罗尼亚'), description=_('费尔南多·迪诺罗尼亚时间')),
        # South Georgia Standard Time;(GMT-02:00, -120)Atlantic/South_Georgia
        'Atlantic/South_Georgia': TimeZoneItem(name='Atlantic/South_Georgia', display=_('大西洋/南乔治亚州'), description=_('南乔治亚标准时间')),

        # Western Greenland Time;(GMT-01:00, -60)America/Godthab
        'America/Godthab': TimeZoneItem(name='America/Godthab', display=_('努克(戈特霍布)'), description=_('格陵兰西部时间')),
        # Eastern Greenland Time;(GMT-01:00, -60)America/Scoresbysund；夏令时 UTC+0
        'America/Scoresbysund': TimeZoneItem(name='America/Scoresbysund', display=_('美洲/斯科斯比松'), description=_('格陵兰岛东部时间')),
        # Cape Verde Time;(GMT-01:00, -60)Atlantic/Cape_Verde
        'Atlantic/Cape_Verde': TimeZoneItem(name='Atlantic/Cape_Verde', display=_('大西洋/佛得角'), description=_('佛得角时间')),

        'GMT': TimeZoneItem(name='GMT', display=_('GMT'), description=_('格林尼治标准时间')),
        # Coordinated Universal Time;
        'UTC': TimeZoneItem(name='UTC', display=_('UTC'), description=_('世界时')),
        # Western European Time; UTC+0:00
        # 'WET': TimeZoneItem(name='WET', display=_('WET'), description=_('西欧标准时间')),

        # Azores Time;(GMT+00:00, 0)Atlantic/Azores
        'Atlantic/Azores': TimeZoneItem(name='Atlantic/Azores', display=_('大西洋/亚速尔群岛'), description=_('亚速尔群岛时间')),

        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Abidjan
        'Africa/Abidjan': TimeZoneItem(name='Africa/Abidjan', display=_('非洲/阿比让'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Accra
        'Africa/Accra': TimeZoneItem(name='Africa/Accra', display=_('非洲/阿克拉'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Banjul
        'Africa/Banjul': TimeZoneItem(name='Africa/Banjul', display=_('非洲/班珠尔'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Bissau
        'Africa/Bissau': TimeZoneItem(name='Africa/Bissau', display=_('非洲/比绍'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Conakry
        'Africa/Conakry': TimeZoneItem(name='Africa/Conakry', display=_('非洲/科纳克里'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Dakar
        'Africa/Dakar': TimeZoneItem(name='Africa/Dakar', display=_('非洲/达喀尔'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Freetown
        'Africa/Freetown': TimeZoneItem(name='Africa/Freetown', display=_('非洲/弗里敦'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Lome
        'Africa/Lome': TimeZoneItem(name='Africa/Lome', display=_('非洲/洛美'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Monrovia
        'Africa/Monrovia': TimeZoneItem(name='Africa/Monrovia', display=_('非洲/蒙罗维亚'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Nouakchott
        'Africa/Nouakchott': TimeZoneItem(name='Africa/Nouakchott', display=_('非洲/努瓦克肖特'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Ouagadougou
        'Africa/Ouagadougou': TimeZoneItem(name='Africa/Ouagadougou', display=_('非洲/瓦加杜古'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Sao_Tome
        'Africa/Sao_Tome': TimeZoneItem(name='Africa/Sao_Tome', display=_('非洲/圣多美'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Africa/Timbuktu
        'Africa/Timbuktu': TimeZoneItem(name='Africa/Timbuktu', display=_('非洲/廷巴克图'), description=_('格林尼治标准时间')),

        # Greenwich Mean Time;(GMT+00:00, 0)Atlantic/Reykjavik
        'Atlantic/Reykjavik': TimeZoneItem(name='Atlantic/Reykjavik', display=_('大西洋/雷克雅未克'), description=_('格林尼治标准时间')),
        # Greenwich Mean Time;(GMT+00:00, 0)Atlantic/St_Helena
        'Atlantic/St_Helena': TimeZoneItem(name='Atlantic/St_Helena', display=_('大西洋/圣海伦娜'), description=_('格林尼治标准时间')),

        # Western European Time;(GMT+01:00, 60)Africa/Casablanca
        'Africa/Casablanca': TimeZoneItem(name='Africa/Casablanca', display=_('非洲/卡萨布兰卡'), description=_('西欧时间')),
        # Western European Time;(GMT+01:00, 60)Atlantic/Canary
        'Atlantic/Canary': TimeZoneItem(name='Atlantic/Canary', display=_('大西洋/加那利群岛'), description=_('西欧时间')),
        # Western European Time;(GMT+01:00, 60)Atlantic/Faeroe
        'Atlantic/Faeroe': TimeZoneItem(name='Atlantic/Faeroe', display=_('大西洋/法罗群岛'), description=_('西欧时间')),

        # Greenwich Mean Time;(GMT+01:00, 60)Europe/Dublin;夏令时=UTC+1,冬季=UTC
        'Europe/Dublin': TimeZoneItem(name='Europe/Dublin', display=_('欧洲/都柏林'), description=_('爱尔兰时间')),
        # Western European Time;(GMT+01:00, 60)Europe/Lisbon
        'Europe/Lisbon': TimeZoneItem(name='Europe/Lisbon', display=_('欧洲/里斯本'), description=_('西欧时间')),
        # Greenwich Mean Time; (GMT+01:00, 60)Europe/London
        'Europe/London': TimeZoneItem(name='Europe/London', display=_('欧洲/伦敦'), description=_('英国时间')),

        # Central European Time;(GMT+01:00, 60)Africa/Algiers
        'Africa/Algiers': TimeZoneItem(name='Africa/Algiers', display=_('非洲/阿尔及尔'), description=_('欧洲中部时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Bangui
        'Africa/Bangui': TimeZoneItem(name='Africa/Bangui', display=_('非洲/班吉'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Douala
        'Africa/Douala': TimeZoneItem(name='Africa/Douala', display=_('非洲/杜阿拉'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Kinshasa
        'Africa/Kinshasa': TimeZoneItem(name='Africa/Kinshasa', display=_('非洲/金沙萨'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Lagos
        'Africa/Lagos': TimeZoneItem(name='Africa/Lagos', display=_('非洲/拉各斯'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Libreville
        'Africa/Libreville': TimeZoneItem(name='Africa/Libreville', display=_('非洲/利伯维尔'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Luanda
        'Africa/Luanda': TimeZoneItem(name='Africa/Luanda', display=_('非洲/罗安达'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Malabo
        'Africa/Malabo': TimeZoneItem(name='Africa/Malabo', display=_('非洲/马拉博'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Ndjamena
        'Africa/Ndjamena': TimeZoneItem(name='Africa/Ndjamena', display=_('非洲/恩贾梅纳'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Niamey
        'Africa/Niamey': TimeZoneItem(name='Africa/Niamey', display=_('非洲/尼亚美'), description=_('西非时间')),
        # Western African Time;(GMT+01:00, 60)Africa/Porto-Novo
        'Africa/Porto-Novo': TimeZoneItem(name='Africa/Porto-Novo', display=_('非洲/波多诺伏'), description=_('西非时间')),
        # Western African Time;(GMT+02:00, 120)Africa/Windhoek
        'Africa/Windhoek': TimeZoneItem(name='Africa/Windhoek', display=_('非洲/温得和克'), description=_('西非时间')),

        # Eastern Greenland Time;(GMT+02:00, 120)Atlantic/Jan_Mayen；夏令时（UTC+2:00），冬季标准时UTC+1:00
        'Atlantic/Jan_Mayen': TimeZoneItem(name='Atlantic/Jan_Mayen', display=_('大西洋/扬马延岛'), description=_('扬马延岛时间')),
        # Central European Time;(GMT+01:00, 60)Africa/Tunis
        'Africa/Tunis': TimeZoneItem(name='Africa/Tunis', display=_('非洲/突尼斯'), description=_('欧洲中部时间')),
        # 'ECT': 'Central European Time',
        # Central European Time;(GMT+02:00, 120)Europe/Amsterdam
        'Europe/Amsterdam': TimeZoneItem(name='Europe/Amsterdam', display=_('欧洲/阿姆斯特丹'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Andorra
        'Europe/Andorra': TimeZoneItem(name='Europe/Andorra', display=_('欧洲/安道尔'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Belgrade
        'Europe/Belgrade': TimeZoneItem(name='Europe/Belgrade', display=_('欧洲/贝尔格莱德'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Berlin
        'Europe/Berlin': TimeZoneItem(name='Europe/Berlin', display=_('欧洲/柏林'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Brussels
        'Europe/Brussels': TimeZoneItem(name='Europe/Brussels', display=_('欧洲/布鲁塞尔'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Budapest
        'Europe/Budapest': TimeZoneItem(name='Europe/Budapest', display=_('欧洲/布达佩斯'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Copenhagen
        'Europe/Copenhagen': TimeZoneItem(name='Europe/Copenhagen', display=_('欧洲/哥本哈根'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Gibraltar
        'Europe/Gibraltar': TimeZoneItem(name='Europe/Gibraltar', display=_('欧洲/直布罗陀'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Luxembourg
        'Europe/Luxembourg': TimeZoneItem(name='Europe/Luxembourg', display=_('欧洲/卢森堡'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Madrid
        'Europe/Madrid': TimeZoneItem(name='Europe/Madrid', display=_('欧洲/马德里'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Malta
        'Europe/Malta': TimeZoneItem(name='Europe/Malta', display=_('欧洲/马耳他'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Monaco
        'Europe/Monaco': TimeZoneItem(name='Europe/Monaco', display=_('欧洲/摩纳哥'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Oslo
        'Europe/Oslo': TimeZoneItem(name='Europe/Oslo', display=_('欧洲/奥斯陆'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Paris
        'Europe/Paris': TimeZoneItem(name='Europe/Paris', display=_('欧洲/巴黎'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Prague
        'Europe/Prague': TimeZoneItem(name='Europe/Prague', display=_('欧洲/布拉格'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Rome
        'Europe/Rome': TimeZoneItem(name='Europe/Rome', display=_('欧洲/罗马'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Stockholm
        'Europe/Stockholm': TimeZoneItem(name='Europe/Stockholm', display=_('欧洲/斯德哥尔摩'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Tirane
        'Europe/Tirane': TimeZoneItem(name='Europe/Tirane', display=_('欧洲/地拉那'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Vaduz
        'Europe/Vaduz': TimeZoneItem(name='Europe/Vaduz', display=_('欧洲/瓦杜兹'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Vienna
        'Europe/Vienna': TimeZoneItem(name='Europe/Vienna', display=_('欧洲/维也纳'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Warsaw
        'Europe/Warsaw': TimeZoneItem(name='Europe/Warsaw', display=_('欧洲/华沙'), description=_('欧洲中部时间')),
        # Central European Time;(GMT+02:00, 120)Europe/Zurich
        'Europe/Zurich': TimeZoneItem(name='Europe/Zurich', display=_('欧洲/苏黎世'), description=_('欧洲中部时间')),

        # 'ART': 'Eastern European Time',
        # Central African Time;(GMT+02:00, 120)Africa/Blantyre
        'Africa/Blantyre': TimeZoneItem(name='Africa/Blantyre', display=_('非洲/布兰太尔'), description=_('非洲中部时间')),
        # Central African Time;(GMT+02:00, 120)Africa/Bujumbura
        'Africa/Bujumbura': TimeZoneItem(name='Africa/Bujumbura', display=_('非洲/布琼布拉'), description=_('非洲中部时间')),
        # Central African Time;(GMT+02:00, 120)Africa/Gaborone
        'Africa/Gaborone': TimeZoneItem(name='Africa/Gaborone', display=_('非洲/哈博罗内'), description=_('非洲中部时间')),
        # Central African Time;(GMT+02:00, 120)Africa/Harare
        'Africa/Harare': TimeZoneItem(name='Africa/Harare', display=_('非洲/哈拉雷'), description=_('非洲中部时间')),
        # South Africa Standard Time;(GMT+02:00, 120)Africa/Johannesburg
        'Africa/Johannesburg': TimeZoneItem(name='Africa/Johannesburg', display=_('非洲/约翰内斯堡'), description=_('南非标准时间')),
        # Central African Time;(GMT+02:00, 120)Africa/Kigali
        'Africa/Kigali': TimeZoneItem(name='Africa/Kigali', display=_('非洲/基加利'), description=_('非洲中部时间')),
        # Central African Time;(GMT+02:00, 120)Africa/Lubumbashi
        'Africa/Lubumbashi': TimeZoneItem(name='Africa/Lubumbashi', display=_('非洲/卢本巴希'), description=_('非洲中部时间')),
        # Central African Time;(GMT+02:00, 120)Africa/Lusaka
        'Africa/Lusaka': TimeZoneItem(name='Africa/Lusaka', display=_('非洲/卢萨卡'), description=_('非洲中部时间')),
        # Central African Time;(GMT+02:00, 120)Africa/Maputo
        'Africa/Maputo': TimeZoneItem(name='Africa/Maputo', display=_('非洲/马普托'), description=_('非洲中部时间')),
        # South Africa Standard Time;(GMT+02:00, 120)Africa/Maseru
        'Africa/Maseru': TimeZoneItem(name='Africa/Maseru', display=_('非洲/马塞卢'), description=_('南非标准时间')),
        # South Africa Standard Time;(GMT+02:00, 120)Africa/Mbabane
        'Africa/Mbabane': TimeZoneItem(name='Africa/Mbabane', display=_('非洲/姆巴巴内'), description=_('南非标准时间')),

        # Eastern European Time;(GMT+03:00, 180)Africa/Cairo
        'Africa/Cairo': TimeZoneItem(name='Africa/Cairo', display=_('非洲/开罗'), description=_('东欧时间')),
        # Eastern European Time;(GMT+02:00, 120)Africa/Tripoli
        'Africa/Tripoli': TimeZoneItem(name='Africa/Tripoli', display=_('非洲/的黎波里'), description=_('东欧时间')),
        # Eastern European Time;(GMT+02:00, 120)Europe/Kaliningrad
        'Europe/Kaliningrad': TimeZoneItem(name='Europe/Kaliningrad', display=_('欧洲/加里宁格勒'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Asia/Amman
        'Asia/Amman': TimeZoneItem(name='Asia/Amman', display=_('亚洲/安曼'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Asia/Beirut
        'Asia/Beirut': TimeZoneItem(name='Asia/Beirut', display=_('亚洲/贝鲁特'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Asia/Damascus
        'Asia/Damascus': TimeZoneItem(name='Asia/Damascus', display=_('亚洲/大马士革'), description=_('东欧时间')),
        # Israel Standard Time;(GMT+03:00, 180)Asia/Jerusalem
        'Asia/Jerusalem': TimeZoneItem(name='Asia/Jerusalem', display=_('亚洲/耶路撒冷'), description=_('以色列时间')),
        # Eastern European Time;(GMT+03:00, 180)Asia/Nicosia
        'Asia/Nicosia': TimeZoneItem(name='Asia/Nicosia', display=_('亚洲/尼科西亚'), description=_('东欧时间')),

        # Central African Time
        # 'CAT': TimeZoneItem(name='', display=_(''), description=_('非洲中部时间')),
        # Eastern European Time;(GMT+03:00, 180)EET
        # 'EET': TimeZoneItem(name='EET', display=_('EET'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Athens
        'Europe/Athens': TimeZoneItem(name='Europe/Athens', display=_('欧洲/雅典'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Bucharest
        'Europe/Bucharest': TimeZoneItem(name='Europe/Bucharest', display=_('欧洲/布加勒斯特'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Chisinau
        'Europe/Chisinau': TimeZoneItem(name='Europe/Chisinau', display=_('欧洲/基希讷乌'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Helsinki
        'Europe/Helsinki': TimeZoneItem(name='Europe/Helsinki', display=_('欧洲/赫尔辛基'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Istanbul
        'Europe/Istanbul': TimeZoneItem(name='Europe/Istanbul', display=_('欧洲/伊斯坦布尔'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Kiev
        'Europe/Kiev': TimeZoneItem(name='Europe/Kiev', display=_('欧洲/基辅'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Minsk
        'Europe/Minsk': TimeZoneItem(name='Europe/Minsk', display=_('欧洲/明斯克'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Riga
        'Europe/Riga': TimeZoneItem(name='Europe/Riga', display=_('欧洲/里加'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Simferopol
        'Europe/Simferopol': TimeZoneItem(name='Europe/Simferopol', display=_('欧洲/辛菲罗波尔'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Sofia
        'Europe/Sofia': TimeZoneItem(name='Europe/Sofia', display=_('欧洲/索非亚'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Tallinn
        'Europe/Tallinn': TimeZoneItem(name='Europe/Tallinn', display=_('欧洲/塔林'), description=_('东欧时间')),
        # Eastern European Time;(GMT+03:00, 180)Europe/Vilnius
        'Europe/Vilnius': TimeZoneItem(name='Europe/Vilnius', display=_('欧洲/维尔纽斯'), description=_('东欧时间')),
        # Moscow Standard Time;(GMT+03:00, 180)Europe/Moscow
        'Europe/Moscow': TimeZoneItem(name='Europe/Moscow', display=_('欧洲/莫斯科'), description=_('莫斯科标准时间')),

        # Eastern African Time;(GMT+03:00, 180)Africa/Addis_Ababa
        'Africa/Addis_Ababa': TimeZoneItem(name='Africa/Addis_Ababa', display=_('非洲/亚的斯亚贝巴'), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Africa/Asmera
        'Africa/Asmera': TimeZoneItem(name='Africa/Asmera', display=_('非洲/阿斯马拉'), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Africa/Dar_es_Salaam
        'Africa/Dar_es_Salaam': TimeZoneItem(name='Africa/Dar_es_Salaam', display=_('非洲/达累斯萨拉姆'), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Africa/Djibouti
        'Africa/Djibouti': TimeZoneItem(name='Africa/Djibouti', display=_('非洲/吉布提'), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Africa/Kampala
        'Africa/Kampala': TimeZoneItem(name='Africa/Kampala', display=_('非洲/坎帕拉'), description=_('东非时间')),
        # Eastern African Time;(GMT+02:00, 120)Africa/Khartoum
        'Africa/Khartoum': TimeZoneItem(name='Africa/Khartoum', display=_('非洲/喀土穆'), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Africa/Mogadishu
        'Africa/Mogadishu': TimeZoneItem(name='Africa/Mogadishu', display=_('非洲/摩加迪沙'), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Africa/Nairobi
        'Africa/Nairobi': TimeZoneItem(name='Africa/Nairobi', display=_('非洲/内罗毕'), description=_('东非时间')),
        # 'EAT': TimeZoneItem(name='', display=_(''), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Indian/Antananarivo
        'Indian/Antananarivo': TimeZoneItem(name='Indian/Antananarivo', display=_('马达加斯加/安塔那那利佛'), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Indian/Comoro
        'Indian/Comoro': TimeZoneItem(name='Indian/Comoro', display=_('印度洋/科摩罗'), description=_('东非时间')),
        # Eastern African Time;(GMT+03:00, 180)Indian/Mayotte
        'Indian/Mayotte': TimeZoneItem(name='Indian/Mayotte', display=_('印度洋/马约特'), description=_('东非时间')),

        # Arabia Standard Time;(GMT+03:00, 180)Asia/Aden
        'Asia/Aden': TimeZoneItem(name='Asia/Aden', display=_('亚洲/亚丁'), description=_('阿拉伯标准时间')),
        # Arabia Standard Time;(GMT+03:00, 180)Asia/Baghdad
        'Asia/Baghdad': TimeZoneItem(name='Asia/Baghdad', display=_('亚洲/巴格达'), description=_('阿拉伯标准时间')),
        # Arabia Standard Time;(GMT+03:00, 180)Asia/Bahrain
        'Asia/Bahrain': TimeZoneItem(name='Asia/Bahrain', display=_('亚洲/巴林'), description=_('阿拉伯标准时间')),
        # Arabia Standard Time;(GMT+03:00, 180)Asia/Kuwait
        'Asia/Kuwait': TimeZoneItem(name='Asia/Kuwait', display=_('亚洲/科威特'), description=_('阿拉伯标准时间')),
        # Arabia Standard Time;(GMT+03:00, 180)Asia/Qatar
        'Asia/Qatar': TimeZoneItem(name='Asia/Qatar', display=_('亚洲/卡塔尔'), description=_('阿拉伯标准时间')),
        # Arabia Standard Time;(GMT+03:00, 180)Asia/Riyadh
        'Asia/Riyadh': TimeZoneItem(name='Asia/Riyadh', display=_('亚洲/利雅得'), description=_('阿拉伯标准时间')),

        # Iran Time;(GMT+03:30, 210)Asia/Tehran
        'Asia/Tehran': TimeZoneItem(name='Asia/Tehran', display=_('亚洲/德黑兰'), description=_('伊朗时间')),
        # 'MET': TimeZoneItem(name='MET', display=_('MET'), description=_('伊朗时间')),

        # Azerbaijan Time;(GMT+04:00, 240)Asia/Baku
        'Asia/Baku': TimeZoneItem(name='Asia/Baku', display=_('亚洲/巴库'), description=_('阿塞拜疆时间')),
        # Gulf Standard Time;(GMT+04:00, 240)Asia/Dubai
        'Asia/Dubai': TimeZoneItem(name='Asia/Dubai', display=_('亚洲/迪拜'), description=_('海湾标准时间')),
        # Gulf Standard Time;(GMT+04:00, 240)Asia/Muscat
        'Asia/Muscat': TimeZoneItem(name='Asia/Muscat', display=_('亚洲/马斯喀特'), description=_('海湾标准时间')),
        # Georgia Time;(GMT+04:00, 240)Asia/Tbilisi
        'Asia/Tbilisi': TimeZoneItem(name='Asia/Tbilisi', display=_('亚洲/第比利斯'), description=_('格鲁吉亚时间')),
        # Armenia Time;(GMT+04:00, 240)Asia/Yerevan
        'Asia/Yerevan': TimeZoneItem(name='Asia/Yerevan', display=_('亚洲/埃里温'), description=_('亚美尼亚时间')),
        # Samara Time;(GMT+04:00, 240)Europe/Samara
        'Europe/Samara': TimeZoneItem(name='Europe/Samara', display=_('欧洲/萨马拉'), description=_('萨马拉时间')),
        # Seychelles Time;(GMT+04:00, 240)Indian/Mahe
        'Indian/Mahe': TimeZoneItem(name='Indian/Mahe', display=_('印度洋/马埃'), description=_('塞舌尔时间')),
        # Mauritius Time;(GMT+04:00, 240)Indian/Mauritius
        'Indian/Mauritius': TimeZoneItem(name='Indian/Mauritius', display=_('印度洋/毛里求斯'), description=_('毛里求斯时间')),
        # Reunion Time;(GMT+04:00, 240)Indian/Reunion
        'Indian/Reunion': TimeZoneItem(name='Indian/Reunion', display=_('印度洋/留尼汪岛'), description=_('留尼汪时间')),
        # 'NET': 'Armenia Time',
        # Afghanistan Time;(GMT+04:30, 270)Asia/Kabul
        'Asia/Kabul': TimeZoneItem(name='Asia/Kabul', display=_('亚洲/喀布尔'), description=_('阿富汗时间')),
        # Aqtau Time;(GMT+05:00, 300)Asia/Aqtau
        'Asia/Aqtau': TimeZoneItem(name='Asia/Aqtau', display=_('亚洲/阿克套'), description=_('哈萨克斯坦西部阿克套时间')),
        # Aqtobe Time;(GMT+05:00, 300)Asia/Aqtobe
        'Asia/Aqtobe': TimeZoneItem(name='Asia/Aqtobe', display=_('亚洲/阿克托别'), description=_('哈萨克斯坦阿克托别时间')),
        # Turkmenistan Time;(GMT+05:00, 300)Asia/Ashgabat
        'Asia/Ashgabat': TimeZoneItem(name='Asia/Ashgabat', display=_('亚洲/阿什哈巴德'), description=_('土库曼斯坦时间')),
        # Turkmenistan Time;(GMT+05:00, 300)Asia/Ashkhabad
        'Asia/Ashkhabad': TimeZoneItem(name='Asia/Ashkhabad', display=_('亚洲/阿什哈巴德'), description=_('土库曼斯坦时间')),
        # Tajikistan Time;(GMT+05:00, 300)Asia/Dushanbe
        'Asia/Dushanbe': TimeZoneItem(name='Asia/Dushanbe', display=_('亚洲/杜尚别'), description=_('塔吉克斯坦时间')),
        # 'PLT': 'Pakistan Time',
        # Pakistan Time;(GMT+05:00, 300)Asia/Karachi
        'Asia/Karachi': TimeZoneItem(name='Asia/Karachi', display=_('亚洲/卡拉奇'), description=_('巴基斯坦时间')),
        # Uzbekistan Time;(GMT+05:00, 300)Asia/Tashkent
        'Asia/Tashkent': TimeZoneItem(name='Asia/Tashkent', display=_('亚洲/塔什干'), description=_('乌兹别克斯坦时间')),
        # Yekaterinburg Time;(GMT+05:00, 300)Asia/Yekaterinburg
        'Asia/Yekaterinburg': TimeZoneItem(name='Asia/Yekaterinburg', display=_('亚洲/叶卡捷琳堡'), description=_('叶卡捷琳堡时间')),
        # French Southern & Antarctic Lands Time;(GMT+05:00, 300)Indian/Kerguelen
        'Indian/Kerguelen': TimeZoneItem(name='Indian/Kerguelen', display=_('印度洋/凯尔盖朗群岛'), description=_('法属南半球和南极领地时间')),
        # Maldives Time;(GMT+05:00, 300)Indian/Maldives
        'Indian/Maldives': TimeZoneItem(name='Indian/Maldives', display=_('印度洋/马尔代夫'), description=_('马尔代夫时间')),
        # Mawson Time;(GMT+05:00, 300)Antarctica/Mawson
        'Antarctica/Mawson': TimeZoneItem(name='Antarctica/Mawson', display=_('南极洲/莫森'), description=_('莫森站时间')),
        # Alma-Ata Time;(GMT+05:00, 300)Asia/Almaty
        'Asia/Almaty': TimeZoneItem(name='Asia/Almaty', display=_('亚洲/阿拉木图'), description=_('哈萨克斯坦东部时间')),

        # India Standard Time;(GMT+05:30, 330)Asia/Calcutta
        'Asia/Calcutta': TimeZoneItem(name='Asia/Calcutta', display=_('亚洲/加尔各答'), description=_('印度标准时间')),
        # 'IST': 'India Standard Time',
        # Sri Lanka Time;(GMT+05:30, 330)Asia/Colombo
        'Asia/Colombo': TimeZoneItem(name='Asia/Colombo', display=_('亚洲/科伦坡'), description=_('斯里兰卡时间')),
        # Nepal Time;(GMT+05:45, 345)Asia/Katmandu
        'Asia/Katmandu': TimeZoneItem(name='Asia/Katmandu', display=_('亚洲/加德满都'), description=_('尼泊尔时区')),

        # Kirgizstan Time;(GMT+06:00, 360)Asia/Bishkek
        'Asia/Bishkek': TimeZoneItem(name='Asia/Bishkek', display=_('亚洲/比什凯克'), description=_('吉尔吉斯斯坦时间')),
        # Indian Ocean Territory Time;(GMT+06:00, 360)Indian/Chagos
        'Indian/Chagos': TimeZoneItem(name='Indian/Chagos', display=_('印度洋/查戈斯'), description=_('印度洋领地时间')),
        # Bangladesh Time;(GMT+06:00, 360)Asia/Dacca, 旧称
        'Asia/Dacca': TimeZoneItem(name='Asia/Dhaka', display=_('亚洲/达卡'), description=_('孟加拉国时间')),
        # Bangladesh Time;(GMT+06:00, 360)Asia/Dhaka
        'Asia/Dhaka': TimeZoneItem(name='Asia/Dhaka', display=_('亚洲/达卡'), description=_('孟加拉国时间')),
        # Bhutan Time;(GMT+06:00, 360)Asia/Thimbu，旧称
        'Asia/Thimbu': TimeZoneItem(name='Asia/Thimphu', display=_('亚洲/廷布'), description=_('不丹时间')),
        # Bhutan Time;(GMT+06:00, 360)Asia/Thimphu
        'Asia/Thimphu': TimeZoneItem(name='Asia/Thimphu', display=_('亚洲/廷布'), description=_('不丹时间')),
        # 'BST': 'Bangladesh Time',
        # Myanmar Time; (GMT+06:30, 390)Asia/Rangoon
        'Asia/Rangoon': TimeZoneItem(name='Asia/Rangoon', display=_('亚洲/仰光'), description=_('缅甸时间')),
        # Cocos Islands Time;(GMT+06:30, 390)Indian/Cocos
        'Indian/Cocos': TimeZoneItem(name='Indian/Cocos', display=_('亚洲/科科斯群岛'), description=_('科科斯群岛时间')),

        # Novosibirsk Time;(GMT+07:00, 420)Asia/Novosibirsk
        'Asia/Novosibirsk': TimeZoneItem(name='Asia/Novosibirsk', display=_('亚洲/新西伯利亚'), description=_('新西伯利亚时间')),
        # Indochina Time;(GMT+07:00, 420)Asia/Bangkok
        'Asia/Bangkok': TimeZoneItem(name='Asia/Bangkok', display=_('亚洲/曼谷'), description=_('泰国时间')),
        # Java Time;(GMT+07:00, 420)Asia/Jakarta
        'Asia/Jakarta': TimeZoneItem(name='Asia/Jakarta', display=_('亚洲/雅加达'), description=_('印度尼西亚西部时间')),
        # Krasnoyarsk Time;(GMT+07:00, 420)Asia/Krasnoyarsk
        'Asia/Krasnoyarsk': TimeZoneItem(name='Asia/Krasnoyarsk', display=_('亚洲/克拉斯诺亚尔斯克'), description=_('俄罗斯克拉斯诺亚尔斯克时间')),
        # Indochina Time;(GMT+07:00, 420)Asia/Phnom_Penh
        'Asia/Phnom_Penh': TimeZoneItem(name='Asia/Phnom_Penh', display=_('亚洲/金边'), description=_('中南半岛时间')),
        # Indochina Time;(GMT+07:00, 420)Asia/Saigon
        'Asia/Saigon': TimeZoneItem(name='Asia/Saigon', display=_('亚洲/胡志明'), description=_('中南半岛时间')),
        # Indochina Time;(GMT+07:00, 420)Asia/Vientiane
        'Asia/Vientiane': TimeZoneItem(name='Asia/Vientiane', display=_('亚洲/万象'), description=_('中南半岛时间')),
        # Christmas Island Time;(GMT+07:00, 420)Indian/Christmas
        'Indian/Christmas': TimeZoneItem(name='Indian/Christmas', display=_('印度洋/圣诞岛'), description=_('圣诞岛时间')),
        # 'VST': 'Indochina Time',
        # Western Standard Time (Australia);(GMT+08:00, 480)Antarctica/Casey
        'Antarctica/Casey': TimeZoneItem(name='Antarctica/Casey', display=_('南极洲/凯西站'), description=_('澳大利亚西部标准时间')),
        # Brunei Time;(GMT+08:00, 480)Asia/Brunei
        'Asia/Brunei': TimeZoneItem(name='Asia/Brunei', display=_('亚洲/文莱'), description=_('文莱时间')),
        # Irkutsk Time;(GMT+08:00, 480)Asia/Irkutsk
        'Asia/Irkutsk': TimeZoneItem(name='Asia/Irkutsk', display=_('亚洲/伊尔库茨克'), description=_('伊尔库茨克时间')),
        # Malaysia Time;(GMT+08:00, 480)Asia/Kuala_Lumpur
        'Asia/Kuala_Lumpur': TimeZoneItem(name='Asia/Kuala_Lumpur', display=_('亚洲/吉隆坡'), description=_('马来西亚时间')),
        # Philippines Time;(GMT+08:00, 480)Asia/Manila
        'Asia/Manila': TimeZoneItem(name='Asia/Manila', display=_('亚洲/马尼拉'), description=_('菲律宾时间')),
        # Hong Kong Time;(GMT+08:00, 480)Asia/Hong_Kong
        'Asia/Hong_Kong': TimeZoneItem(name='Asia/Hong_Kong', display=_('亚洲/中国香港'), description=_('香港时间')),
        # China Standard Time;(GMT+08:00, 480)Asia/Macao
        'Asia/Macao': TimeZoneItem(name='Asia/Macao', display=_('亚洲/中国澳门'), description=_('中国北京时间')),
        # China Standard Time;(GMT+08:00, 480)Asia/Shanghai
        'Asia/Shanghai': TimeZoneItem(name='Asia/Shanghai', display=_('亚洲/中国上海'), description=_('中国北京时间')),
        # China Standard Time;(GMT+08:00, 480)Asia/Taipei
        'Asia/Taipei': TimeZoneItem(name='Asia/Taipei', display=_('亚洲/中国台北'), description=_('中国北京时间')),
        # Singapore Time;(GMT+08:00, 480)Asia/Singapore
        'Asia/Singapore': TimeZoneItem(name='Asia/Singapore', display=_('亚洲/新加坡'), description=_('新加坡时间')),
        # Borneo Time;(GMT+08:00, 480)Asia/Ujung_Pandang,现指 望加锡（Asia/Makassar）
        'Asia/Ujung_Pandang': TimeZoneItem(name='Asia/Makassar', display=_('亚洲/望加锡'), description=_('印度尼西亚中部时间')),
        # Ulaanbaatar Time;(GMT+08:00, 480)Asia/Ulaanbaatar
        'Asia/Ulaanbaatar': TimeZoneItem(name='Asia/Ulaanbaatar', display=_('亚洲/乌兰巴托'), description=_('乌兰巴托时间')),
        # Ulaanbaatar Time;(GMT+08:00, 480)Asia/Ulan_Bator,旧
        'Asia/Ulan_Bator': TimeZoneItem(name='Asia/Ulaanbaatar', display=_('亚洲/乌兰巴托'), description=_('乌兰巴托时间')),
        # Western Standard Time (Australia);(GMT+08:00, 480)Australia/Perth
        'Australia/Perth': TimeZoneItem(name='Australia/Perth', display=_('澳大利亚/珀斯'), description=_('澳大利亚西部标准时间')),
        # 'CTT': 'China Standard Time',
        # Jayapura Time;(GMT+09:00, 540)Asia/Jayapura
        'Asia/Jayapura': TimeZoneItem(name='Asia/Jayapura', display=_('亚洲/查亚普拉'), description=_('印度尼西亚东部时间')),
        # 朝鲜 Standard Time;(GMT+09:00, 540)Asia/Pyongyang
        'Asia/Pyongyang': TimeZoneItem(name='Asia/Pyongyang', display=_('亚洲/平壤'), description=_('朝鲜标准时间')),
        # Korea Standard Time;(GMT+09:00, 540)Asia/Seoul
        'Asia/Seoul': TimeZoneItem(name='Asia/Seoul', display=_('亚洲/首尔'), description=_('韩国标准时间')),
        # Japan Standard Time;(GMT+09:00, 540)Asia/Tokyo
        'Asia/Tokyo': TimeZoneItem(name='Asia/Tokyo', display=_('亚洲/东京'), description=_('日本标准时间')),
        # Yakutsk Time;(GMT+09:00, 540)Asia/Yakutsk
        'Asia/Yakutsk': TimeZoneItem(name='Asia/Yakutsk', display=_('亚洲/雅库茨克'), description=_('雅库茨克时间')),
        # 'JST': 'Japan Standard Time',
        # Palau Time;(GMT+09:00, 540)Pacific/Palau
        'Pacific/Palau': TimeZoneItem(name='Pacific/Palau', display=_('太平洋/帕劳'), description=_('帕劳时间')),
        # 'ACT': 'Central Standard Time (Northern Territory)',
        # Central Standard Time (South Australia);(GMT+09:30, 570)Australia/Adelaide
        'Australia/Adelaide': TimeZoneItem(name='Australia/Adelaide', display=_('澳大利亚/阿德莱德'), description=_('澳大利亚中部标准时间')),
        # Central Standard Time (South Australia/New South Wales);(GMT+09:30, 570)Australia/Broken_Hill
        'Australia/Broken_Hill': TimeZoneItem(name='Australia/Broken_Hill', display=_('澳大利亚/布罗肯·希尔'), description=_('澳大利亚中部标准时间')),
        # Central Standard Time (Northern Territory);(GMT+09:30, 570)Australia/Darwin
        'Australia/Darwin': TimeZoneItem(name='Australia/Darwin', display=_('澳大利亚/达尔文'), description=_('澳大利亚中部标准时间')),
        # 'AET': 'Eastern Standard Time (New South Wales)',
        # Dumont-d'Urville Time;(GMT+10:00, 600)Antarctica/DumontDUrville
        'Antarctica/DumontDUrville': TimeZoneItem(name='Antarctica/DumontDUrville', display=_('南极洲/杜蒙·迪维尔站'), description=_('杜蒙·迪维尔时间')),
        # Vladivostok Time;(GMT+10:00, 600)Asia/Vladivostok
        'Asia/Vladivostok': TimeZoneItem(name='Asia/Vladivostok', display=_('亚洲/符拉迪沃斯托克'), description=_('海参崴时间')),
        # Eastern Standard Time (Queensland);(GMT+10:00, 600)Australia/Brisbane
        'Australia/Brisbane': TimeZoneItem(name='Australia/Brisbane', display=_('澳大利亚/布里斯班'), description=_('澳大利亚东部标准时间')),
        # Eastern Standard Time (Tasmania);(GMT+10:00, 600)Australia/Hobart
        'Australia/Hobart': TimeZoneItem(name='Australia/Hobart', display=_('澳大利亚/霍巴特'), description=_('澳大利亚东部时间')),
        # Eastern Standard Time (New South Wales);(GMT+10:00, 600)Australia/Sydney
        'Australia/Sydney': TimeZoneItem(name='Australia/Sydney', display=_('澳大利亚/悉尼'), description=_('澳大利亚东部时间')),
        # Chamorro Standard Time;(GMT+10:00, 600)Pacific/Guam
        'Pacific/Guam': TimeZoneItem(name='Pacific/Guam', display=_('太平洋/关岛'), description=_('查莫罗标准时间')),
        # Papua New Guinea Time;(GMT+10:00, 600)Pacific/Port_Moresby
        'Pacific/Port_Moresby': TimeZoneItem(name='Pacific/Port_Moresby', display=_('太平洋/莫尔兹比港'), description=_('巴布亚新几内亚时间')),
        # Chamorro Standard Time;(GMT+10:00, 600)Pacific/Saipan
        'Pacific/Saipan': TimeZoneItem(name='Pacific/Saipan', display=_('太平洋/塞班岛'), description=_('查莫罗标准时间')),
        # Truk Time;(GMT+10:00, 600)Pacific/Truk, 已过时,重新命名为 Pacific/Chuuk
        'Pacific/Truk': TimeZoneItem(name='Pacific/Chuuk', display=_('太平洋/楚克'), description=_('密克罗尼西亚楚克时间')),
        # Load Howe Standard Time;(GMT+10:30, 630)Australia/Lord_Howe
        'Australia/Lord_Howe': TimeZoneItem(name='Australia/Lord_Howe', display=_('澳大利亚/豪勋爵岛'), description=_('豪勋爵岛时间')),
        # Magadan Time;(GMT+11:00, 660)Asia/Magadan
        'Asia/Magadan': TimeZoneItem(name='Asia/Magadan', display=_('亚洲/马加丹'), description=_('马加丹时间')),
        # Vanuatu Time;(GMT+11:00, 660)Pacific/Efate
        'Pacific/Efate': TimeZoneItem(name='Pacific/Efate', display=_('太平洋/埃法特岛'), description=_('瓦努阿图时间')),
        # Solomon Is. Time;(GMT+11:00, 660)Pacific/Guadalcanal
        'Pacific/Guadalcanal': TimeZoneItem(name='Pacific/Guadalcanal', display=_('太平洋/瓜达尔卡纳尔岛'), description=_('所罗门群岛时间')),
        # Kosrae Time;(GMT+11:00, 660)Pacific/Kosrae
        'Pacific/Kosrae': TimeZoneItem(name='Pacific/Kosrae', display=_('太平洋/科斯雷岛'), description=_('科斯雷时间')),
        # New Caledonia Time;(GMT+11:00, 660)Pacific/Noumea
        'Pacific/Noumea': TimeZoneItem(name='Pacific/Noumea', display=_('太平洋/努美阿'), description=_('新喀里多尼亚时间')),
        # Ponape Time;(GMT+11:00, 660)Pacific/Ponape; 推荐使用 "Pacific/Pohnpei"
        'Pacific/Ponape': TimeZoneItem(name='Pacific/Pohnpei', display=_('太平洋/波纳佩'), description=_('波纳佩岛时间')),
        # 'SST': 'Solomon Is. Time',
        # Norfolk Time;(GMT+11:00, 660)Pacific/Norfolk
        'Pacific/Norfolk': TimeZoneItem(name='Pacific/Norfolk', display=_('太平洋/诺福克'), description=_('诺福克岛时间')),
        # New Zealand Standard Time;(GMT+12:00, 720)Antarctica/McMurdo
        'Antarctica/McMurdo': TimeZoneItem(name='Antarctica/McMurdo', display=_('南极洲/麦克默多站'), description=_('新西兰标准时间')),
        # Anadyr Time;(GMT+12:00, 720)Asia/Anadyr
        'Asia/Anadyr': TimeZoneItem(name='Asia/Anadyr', display=_('亚洲/阿纳德尔'), description=_('阿纳德尔时间')),
        # Petropavlovsk-Kamchatski Time;(GMT+12:00, 720)Asia/Kamchatka
        'Asia/Kamchatka': TimeZoneItem(name='Asia/Kamchatka', display=_('亚洲/堪察加半岛'), description=_('堪察加-彼得罗巴甫洛夫斯克时间')),
        # 'NST': 'New Zealand Standard Time',
        # New Zealand Standard Time;(GMT+12:00, 720)Pacific/Auckland
        'Pacific/Auckland': TimeZoneItem(name='Pacific/Auckland', display=_('太平洋/奥克兰'), description=_('新西兰标准时间')),
        # Fiji Time;(GMT+12:00, 720)Pacific/Fiji
        'Pacific/Fiji': TimeZoneItem(name='Pacific/Fiji', display=_('太平洋/斐济'), description=_('斐济时间')),
        # Tuvalu Time;(GMT+12:00, 720)Pacific/Funafuti
        'Pacific/Funafuti': TimeZoneItem(name='Pacific/Funafuti', display=_('太平洋/富纳富提'), description=_('图瓦卢时间')),
        # Marshall Islands Time;(GMT+12:00, 720)Pacific/Majuro
        'Pacific/Majuro': TimeZoneItem(name='Pacific/Majuro', display=_('太平洋/马朱罗'), description=_('马绍尔群岛时间')),
        # Nauru Time;(GMT+12:00, 720)Pacific/Nauru
        'Pacific/Nauru': TimeZoneItem(name='Pacific/Nauru', display=_('太平洋/瑙鲁'), description=_('瑙鲁时间')),
        # Gilbert Is. Time;(GMT+12:00, 720)Pacific/Tarawa
        'Pacific/Tarawa': TimeZoneItem(name='Pacific/Tarawa', display=_('太平洋/塔拉瓦'), description=_('基里巴斯时间')),
        # Wake Time;(GMT+12:00, 720)Pacific/Wake
        'Pacific/Wake': TimeZoneItem(name='Pacific/Wake', display=_('太平洋/威克岛'), description=_('威克岛时间')),
        # Wallis & Futuna Time;(GMT+12:00, 720)Pacific/Wallis
        'Pacific/Wallis': TimeZoneItem(name='Pacific/Wallis', display=_('太平洋/瓦利斯'), description=_('瓦利斯和富图纳群岛时间')),
        # Chatham Standard Time;(GMT+12:45, 765)Pacific/Chatham; 夏令时UTC+13:45
        'Pacific/Chatham': TimeZoneItem(name='Pacific/Chatham', display=_('太平洋/查塔姆'), description=_('查塔姆群岛时间')),
        # Phoenix Is. Time;(GMT+13:00, 780)Pacific/Enderbury
        'Pacific/Enderbury': TimeZoneItem(name='Pacific/Enderbury', display=_('太平洋/安德伯里'), description=_('菲尼克斯群岛时间')),
        # Tonga Time;(GMT+13:00, 780)Pacific/Tongatapu
        'Pacific/Tongatapu': TimeZoneItem(name='Pacific/Tongatapu', display=_('太平洋/汤加塔普'), description=_('汤加时间')),

        # Tokelau Time,(GMT+13:00, 780)Pacific/Fakaofo
        'Pacific/Fakaofo': TimeZoneItem(name='Pacific/Fakaofo', display=_('太平洋/法考福'), description=_('托克劳时间')),
        # West Samoa Time
        # 'MIT': TimeZoneItem(name='Pacific/Apia', display=_('太平洋/阿皮亚'), description=_('西萨摩亚时间')),
        # West Samoa Time, (GMT+13:00, 780)
        'Pacific/Apia': TimeZoneItem(name='Pacific/Apia', display=_('太平洋/阿皮亚'), description=_('西萨摩亚时间')),

        # Line Is. Time;(GMT+14:00, 840)Pacific/Kiritimati
        'Pacific/Kiritimati': TimeZoneItem(name='Pacific/Kiritimati', display=_('太平洋/基里蒂马蒂'), description=_('莱恩群岛时间')),
    }

    @staticmethod
    def offset_minutes(off: timedelta):
        if off is not None:
            mm, ss = divmod(off, timedelta(minutes=1))
            return mm

        return None

    @classmethod
    def available_timezones(cls) -> Dict[str, TimeZoneItem]:
        if hasattr(cls, '_available_timezones'):
            return cls._available_timezones

        cls._available_timezones = {
            tz_item.name: tz_item for tz_item in cls.TIMEZONES.values()
        }
        return cls._available_timezones

    @staticmethod
    def choices() -> List[Tuple[str, str]]:
        tz_choices = []
        for tz_item in OracleTimezone.available_timezones().values():
            try:
                tz_choices.append((tz_item.name, tz_item.display_detail()))
            except Exception as e:
                pass

        return tz_choices

    @staticmethod
    def tz_display(tz_name: str) -> Optional[str]:
        zones = OracleTimezone.available_timezones()
        tz_item = zones.get(tz_name, None)
        if tz_item is None:
            return None

        return tz_item.display_detail()
